import { addDomEvent, offset, preventDefaultException } from '../util/dom'

const DEFAULT_OPTION = {
  startX: 0,
  startY: 0,
  scrollX: false,
  scrollY: true,
  freeScroll: false,
  diretionLockThreshold: 5,
  eventPassThrough: '',
  click: false,
  /**
   * 支持任何一个方向
   * bounce: {
   *   top: true,
   *   bottom: true,
   *   left: true,
   *   right: true
   * }
   */
  bounce: true,
  bounceTime: 800,
  momentum: true,
  momentumLimitTime: 300,
  momentumLimitDistance: 15,
  swipeTime: 2500,
  swipeBounceTime: 500,
  deceleration: 0.0015,
  probeType: 2,
  preventDefault: true,
  preventDefaultException: {
    tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT|AUDIO)$/
  },
  stopPropagation: false,
  useTransition: true,
  enable: true,
  // 滚动事件是否绑定到wrapper，默认是window
  bindToWrapper: false,
  pullDownRefresh: false,
  /**
   * 下拉刷新
   * pullDownRefresh: {
   *   threshold: 60,
   *   stop: 40
   * }
   */
  pullUpLoad: false,
  /**
   * 上拉加载
   * pullUpLoad: {
   *   threshold: 0
   * }
   */
  snap: false
  /**
   * 轮播
   * snap: {
   *   threshold: 30,
   *   interval: 3000,
   *   loop: true,
   *   autoPlay: true,
   *   stepX: 100,
   *   stepY: 100
   * }
   */
}

export function initMixin (GScroll) {
  GScroll.prototype._init = function (options) {
    this._handleOptions(options)

    this.x = 0
    this.y = 0
    this.directionX = 0
    this.directionY = 0

    this._addDomEvents()

    this.refresh()

    if (!this.options.snap) {
      this.scrollTo(this.options.startX, this.options.startY)
    }

    this.enable()
  }

  GScroll.prototype._addDomEvents = function () {
    let eventOperation = addDomEvent
    this._handleDomEvents(eventOperation)
  }

  GScroll.prototype._handleDomEvents = function (eventOperation) {
    let target = this.options.bindToWrapper ? this.wrapper : window

    if (this.options.click) {
      eventOperation(this.wrapper, 'click', this, true)
    }

    eventOperation(this.wrapper, 'mousedown', this)
    eventOperation(target, 'mousemove', this)
    eventOperation(target, 'mousecancel', this)
    eventOperation(target, 'mouseup', this)

    eventOperation(this.wrapper, 'touchstart', this)
    eventOperation(target, 'touchmove', this)
    eventOperation(target, 'touchcancel', this)
    eventOperation(target, 'touchend', this)

    eventOperation(this.scroller, 'transitionend', this)
  }

  GScroll.prototype.handleEvent = function (e) {
    switch (e.type) {
      case 'touchstart':
      case 'mousedown':
        this._start(e)
        break
      case 'touchmove':
      case 'mousemove':
        this._move(e)
        break
      case 'touchend':
      case 'mouseup':
      case 'touchcancel':
      case 'mousecancel':
        this._end(e)
        break
      case 'transitionend':
        this._transitionEnd(e)
        break
      case 'click':
        if (this.enable && !e._constructed) {
          if (preventDefaultException(e.target, this.options.preventDefaultException)) {
            e.preventDefault()
            e.stopPropagation()
          }
        }
    }
  }

  GScroll.prototype._handleOptions = function (options) {
    this.options = Object.assign({}, DEFAULT_OPTION, options)

    this.hasHorizontalScroll = this.options.scrollX
    this.hasVerticalScroll = this.options.scrollY

    if (this.options.pullDownRefresh) {
      this.openPullDown()
    }
    if (this.options.pullUpLoad) {
      this.openPullUp()
    }
    if (this.options.snap) {
      this._initSnap()
    }

    this.options.preventDefault = !this.options.eventPassThrough && this.options.preventDefault

    // 如果配置eventPassThrough，就锁定其中一个方向
    this.options.scrollX = this.options.eventPassThrough === 'horizontal' ? false : this.options.scrollX
    this.options.scrollY = this.options.eventPassThrough === 'vertical' ? false : this.options.scrollY

    // 配置eventPassThrough还需要锁定方向机制
    this.options.freeScroll = this.options.freeScroll && !this.options.eventPassThrough
    this.options.diretionLockThreshold = this.options.eventPassThrough ? 0 : this.options.diretionLockThreshold
  }

  GScroll.prototype.refresh = function (e) {
    this.wrapperWidth = this.wrapper.offsetWidth
    this.wrapperHeight = this.wrapper.offsetHeight
    this.scrollerWidth = this.scroller.offsetWidth
    this.scrollerHeight = this.scroller.offsetHeight

    this.minScrollX = 0
    this.maxScrollX = this.wrapperWidth - this.scrollerWidth
    this.minScrollY = 0
    this.maxScrollY = this.wrapperHeight - this.scrollerHeight

    this.wrapperOffset = offset(this.wrapper)

    this.trigger('refresh')
  }

  GScroll.prototype.enable = function () {
    this.enabled = true
  }

  GScroll.prototype.disable = function () {
    this.enabled = false
  }
}
